package com.ran.java_gobang.game;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ran.java_gobang.game.response.MatchResponse;
import com.ran.java_gobang.model.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: ran
 * Date: 2025-08-28
 * Time: 21:41
 */

@Slf4j
@Component
// 表示一个匹配器(匹配队列), 用这个类来实现匹配功能
public class Matcher {

    @Autowired
    private OnlineUserManager onlineUserManager;


    private ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    private RoomManager roomManager;

    // 创建三个匹配队列
    private Queue<User> nomalQueue = new LinkedList<>();
    private Queue<User> highQueue = new LinkedList<>();
    private Queue<User> veryHighQueue = new LinkedList<>();

    public void add(User user) {
        try {
            if (user.getScore() < 2000) {
                synchronized (nomalQueue) {
                    nomalQueue.offer(user);
                    nomalQueue.notify();
                }
                log.info("玩家: " + user.getUserName() + " 加入到了新手队列 nomalQueue 中!");
            }else if (user.getScore() >= 2000 && user.getScore() < 3000) {
                synchronized (highQueue) {
                    highQueue.offer(user);
                    highQueue.notify();
                }
                log.info("玩家: " + user.getUserName() + " 加入到了中手队列 highQueue 中!");
            }else {
                synchronized (veryHighQueue) {
                    veryHighQueue.offer(user);
                    veryHighQueue.notify();
                }
                log.info("玩家: " + user.getUserName() + " 加入到了高手队列 veryHighQueue 中!");
            }
        }catch (NullPointerException e) {
            log.error("用户未登录, e",e);
            throw new RuntimeException("玩家未登录!");
        }

    }


    // 玩家点击停止匹配, 把玩家从匹配队列中删除
    public void remove(User user) {
        if (user.getScore() < 2000) {
            synchronized (nomalQueue) {
                nomalQueue.remove(user);
            }
            log.info("玩家: " + user.getUserName() + " 从新手队列 nomalQueue 中删除!");
        }else if (user.getScore() >= 2000 && user.getScore() < 3000) {
            synchronized (highQueue) {
                highQueue.remove(user);
            }
            log.info("玩家: " + user.getUserName() + " 从中手队列 highQueue 中删除!");
        }else {
            synchronized (veryHighQueue) {
                veryHighQueue.remove(user);
            }
            log.info("玩家: " + user.getUserName() + " 从高手队列 veryHighQueue 中删除!");
        }
    }



    // 构造方法里创建三个线程来时刻扫描三个队列情况
    public Matcher() {

        Thread thread1 = new Thread(){
            @Override
            public void run() {
                while (true) {
                    handlerMatch(nomalQueue);
                }
            }
        };
        thread1.start();

        Thread thread2 = new Thread(){
            @Override
            public void run() {
                while (true) {
                    handlerMatch(highQueue);
                }
            }
        };
        thread2.start();
        Thread thread3 = new Thread(){
            @Override
            public void run() {
                while (true) {
                    handlerMatch(veryHighQueue);
                }
            }
        };
        thread3.start();


    }

    // 处理匹配情况
    private void handlerMatch(Queue<User> matchQueue) {
        synchronized (matchQueue) {
            try {
                // 1. 人少于2个一直等待 那么等待唤醒
                // 如果空列空的时候, 往队列添加一个元素不能唤醒, 所以这时需要 while 再次判断是否人数大于2
                while (matchQueue.size() < 2) {
                    matchQueue.wait(); // 等待大于两个人唤醒
                }
                // 2. 从队列中取出两个玩家
                User player1 = matchQueue.poll();
                User player2 = matchQueue.poll();
                log.info("匹配到两个玩家: " + player1.getUserName() + " , " + player2.getUserName());
                // 3. 获取玩家的websocket 会话, 然后告诉玩家你匹配到了
                WebSocketSession session1 = onlineUserManager.getFromGameHall(player1.getUserId());
                WebSocketSession session2 = onlineUserManager.getFromGameHall(player2.getUserId());

                // 判断用户1是否在线, 理论上是在线的, 前面掉线已经从匹配队列删除, 但这里要再次判断一次, 更安全
                if (session1 == null) {
                    // 玩家1 掉线重新把 玩家2 加入匹配队列
                    matchQueue.offer(player2);
                    return;
                }
                if (session2 == null) {
                    // 玩家2 掉线重新把 玩家1 加入匹配队列
                    matchQueue.offer(player1);
                    return;
                }
                // 两个玩家是同一个人, 理论上不存在, 再次判断, 以免前面逻辑出现bug带来严重后果
                // 1) 玩家下线移除队列     2) 禁止了多开
                if (session1 == session2) {
                    // 把其中随意一个放回匹配队列
                    matchQueue.offer(player1);
                    return;
                }

                // 4. TODO 放到同一个游戏房间

                Room room = new Room();
                roomManager.add(room,player1.getUserId(),player2.getUserId());

                // 5. 告诉玩家匹配到对手了
                // 两个玩家都要告知
                session1.sendMessage(send());
                session2.sendMessage(send());
            } catch (IOException e) {
                log.error("捕捉到JSON转换/IO异常, e: ", e);
            } catch (InterruptedException e) {
                log.error("wait等待异常终止异常, e: ", e);
            }
        }
    }
    private TextMessage send() throws JsonProcessingException {
        MatchResponse response = new MatchResponse();
        response.setOk(true);
        response.setMessage("matchSuccess");
        String json = objectMapper.writeValueAsString(response);
        return new TextMessage(json);
    }
}
